package com.apes.fn.scm.crossCompany.transfer.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.apes.fn.scm.crossCompany.transfer.model.*;
import com.apes.fn.scm.crossCompany.transfer.repository.*;
import com.apes.framework.api.DomainService;
import com.apes.framework.api.SpringManager;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.logger.ApesLogger;
import com.apes.framework.jpa.logger.ApesLoggerService;
import com.apes.framework.jpa.spec.JpaDsl;
import com.apes.framework.jpa.spec.model.Filter;
import com.apes.framework.jpa.spec.model.Group;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.event.Listener;
import com.apes.framework.plugin.outbox.OutboxPayloadWrapper;
import com.apes.framework.plugin.outbox.OutboxSubscriberService;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.*;
import com.apes.scm.account.account.model.*;
import com.apes.scm.account.account.repository.InventoryBatchRepository;
import com.apes.scm.account.account.repository.StockRepository;
import com.apes.scm.account.account.service.InventoryService;
import com.apes.scm.account.account.service.ProductAccountService;
import com.apes.scm.account.method.Batch;
import com.apes.scm.account.method.BatchMethod;
import com.apes.scm.account.transit.DepositInTransitService;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.contract.repository.ContractRepository;
import com.apes.scm.contract.service.ContractService;
import com.apes.scm.masterdata.enumeration.model.Enumeration;
import com.apes.scm.masterdata.enumeration.repository.BusinessParamRepository;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.frame.model.DeptEnum;
import com.apes.scm.masterdata.frame.service.StoreService;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.party.repository.PartyRoleRepository;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.model.ProductUom;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import com.apes.scm.masterdata.product.repository.ProductUomRepository;
import com.apes.scm.masterdata.stock.model.Location;
import com.apes.scm.masterdata.stock.repository.LocationRepository;
import com.apes.scm.rbac.model.User;
import com.apes.scm.rbac.repository.UserRepository;
import com.apes.scm.stock.transfer.model.Pick;
import com.apes.scm.stock.transfer.model.PickItem;
import com.apes.scm.stock.transfer.model.Transfer;
import com.apes.scm.stock.transfer.repository.PickRepository;
import com.apes.scm.stock.transfer.repository.TransferRepository;
import com.apes.scm.voucher.model.Voucher;
import com.apes.scm.voucher.model.VoucherItem;
import com.apes.scm.voucher.service.BusinessType;
import com.apes.scm.voucher.service.VoucherType;
import com.apes.scm.voucher.service.builder.CrossTransferVoucherBuilder;
import com.apes.scm.yy.QueryCommonService;
import com.google.common.util.concurrent.AtomicDouble;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import static java.lang.StrictMath.abs;
import static java.util.Comparator.comparing;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

@Service("crossCompanyTransferNewService")
public class CrossCompanyTransferNewService extends DomainService {

    @Autowired
    private CrossCompanyTransferNewRepository crossCompanyTransferRepository;

    @Autowired
    private ProductAccountService productAccountService;

    @Autowired
    private InventoryBatchRepository inventoryBatchRepository;

    @Autowired
    private LocationRepository locationRepository;

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private StockRepository stockRepository;

    @Autowired
    private StoreService storeService;

    @Autowired
    private InventoryService inventoryService;

    @Autowired
    private ContractService contractService;

    @Autowired
    private PickRepository pickRepository;

    @Autowired
    private TransferBatchRepository transferBatchRepository;

    @Autowired
    private TransferProductRepository transferProductRepository;

    @Autowired
    private QueryCommonService queryCommonService;

    @Autowired
    private PrintRecordRepository printRecordRepository;
    @Autowired
    private CrossTransferVoucherBuilder crossTransferVoucherBuilder;
    @Autowired
    private PartyRoleRepository partyRoleRepository;
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private TransferBatchService transferBatchService;
    @Autowired
    private DepositInTransitService depositInTransitService;
    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private ProductUomRepository productUomRepository;
    @Autowired
    private CrossCompanyTransferItemNewRepository crossCompanyTransferItemNewRepository;

    /**
     * 保存
     *
     * @param request
     * @return
     */
    private CrossCompanyTransferNew save(SimpleRequest request) {
        CrossCompanyTransferNew transfer = request.getO(CrossCompanyTransferNew.class);
        Assert.isTrue(!(transfer.getCrossCompanyTransferItems().size() > 100), "调拨商品上限100条！超100请从 [批量补货] 功能导入");
        storeService.judgeFCKBJ(transfer.getReceiptLocation());
        storeService.judgeFCKBJ(transfer.getShipLocation());
        if (!this.canDumpReceiptLocation(transfer.getShipLocation()).contains(transfer.getReceiptLocation().getId())) throw new RuntimeException("收货仓不在发货仓的发货范围内，请重新选择收货仓！");

        // 发货仓库 的公司
        transfer.setCompany(transfer.getShipLocation().getCompany());
        transfer.setState("sent");

        //获取调拨范围
        String export = invoke("scm.transferProductService.accordLCompanyChangeOperation", MapUtil.mapper("id", transfer.getShipLocation().getId()));
        String reception = invoke("scm.transferProductService.accordLCompanyChangeOperation", MapUtil.mapper("id", transfer.getReceiptLocation().getId()));
        List<TransferProduct> transferProductList = transferProductRepository.findByALL(export, reception);
        boolean flag = transferProductList.stream().anyMatch(e->e.getSupplier() == null);

        if (transferProductList.size() == 0) {
            if (transfer.isAuto()) return null;
            throw new RuntimeException("可调拨商品配置表未找到有效供应商");
        }
        List<PartyRole> suppliers = new ArrayList<>();
        /**去重**/
        if (!flag){
            transferProductList = transferProductList.stream().collect(
                    collectingAndThen(toCollection(() -> new TreeSet<>(comparing(transferProduct->transferProduct.getSupplier().getId()))), ArrayList::new));
            suppliers = transferProductList.stream().map(e->e.getSupplier()).collect(Collectors.toList());
        }

        boolean checkContract = false;
        //赋能--直营、子公司、合伙人，查对应合同
        if ("001073".equals(export)&& !"001073".equals(reception)) {
            checkContract = true;
            if (flag) {
                suppliers = findAllSupplier();
            } else {
                //有合同的供应商
                transferProductList = checkTransferProduct(transferProductList,true);
                suppliers = transferProductList.stream().map(e->e.getSupplier()).collect(Collectors.toList());
            }
        }
        if (transfer.getCreateUid() == null) transfer.setCreateUid(request.getPerson());
        transfer.setUserId(userRepository.findOne(JpaDsl.toCriteriaByEq("person.id", transfer.getCreateUid().getId())).get().getId() + "");
        transfer = crossCompanyTransferRepository.saveAndFlush(transfer);
        // 找批次
        List<String> supplierIds = suppliers.stream().distinct().map(singleSupplier -> {return singleSupplier.getId();}).collect(Collectors.toList());
        this.findInventoryBatch(transfer, supplierIds, flag, checkContract);

        // 变动可用数、转入制单数、未达账
        changeUseQty(transfer, 1);

        checkInventoryBatch(transfer);
        return transfer;
    }

    public String safetyGapCreateCross(SimpleRequest request) {
        CrossCompanyTransferNew cross = request.getO(CrossCompanyTransferNew.class);
        Assert.isTrue(!(cross.getCrossCompanyTransferItems().size() > 100), "调拨商品上限100条！超100请从 [批量补货] 功能导入");
        cross.setState("sent");
        cross.setCompany(cross.getShipLocation().getCompany());
        boolean empowermentToNoEmpowerment = cross.getEmpowermentToNoEmpowerment();
        boolean existsTransferProductSupplierIsNull = cross.getExistsTransferProductSupplierIsNull();
        List<String> transferProductSuppliers = cross.getTransferProductSuppliers();


        cross = crossCompanyTransferRepository.saveAndFlush(cross);
        this.insertLogger(cross.getId(), cross.getInnerBusinessType(),"创建", cross.getCreateUid().getId());

        // 找批次
        if (existsTransferProductSupplierIsNull) transferProductSuppliers = findAllSupplier().stream().distinct().map(singleSupplier -> {return singleSupplier.getId();}).collect(Collectors.toList());
        this.findInventoryBatch(cross, transferProductSuppliers, existsTransferProductSupplierIsNull, empowermentToNoEmpowerment);

        // 变动可用数、转入制单数、未达账
        changeUseQty(cross, 1);

        // 核对批次和明细是否一致
//        checkInventoryBatch(cross);


        SimpleRequest sendApprove = new SimpleRequest();
        cross.setApproveUid(cross.getCreateUid());
        sendApprove.setData(cross);

        // 审核
        CrossCompanyTransferNew approveAfterCross = this.approve(sendApprove);
        this.insertLogger(approveAfterCross.getId(), approveAfterCross.getInnerBusinessType(), "审核", approveAfterCross.getApproveUid().getId());

        // 要货批量转储修改要货明细、生成扩展表
        this.batchRequireDumpUpdateRequireQty(approveAfterCross);
        return approveAfterCross.getId();
    }

    private void insertLogger(String businessKey, String businessType, String message, String operatorId) {
        List<User> user = userRepository.findByPartyRoleId(operatorId);
        if (user.isEmpty()) throw new RuntimeException("根据操作员未找到用户 ！操作员编码：" + operatorId);
        ApesLogger apesLogger = new ApesLogger();
        apesLogger.setBusinessKey(businessKey);
        apesLogger.setBusinessType(businessType);
        apesLogger.setOperate(message);
        apesLogger.setBusinessDate(new Date());
        apesLogger.setOperator_id(user.get(0).getId());
        SimpleRequest simpleRequest = new SimpleRequest();
        simpleRequest.setData(apesLogger);
        getBean(ApesLoggerService.class).save(simpleRequest);
    }

    // 获取发货仓的收货仓范围
    private List canDumpReceiptLocation(Location shipLocation) {
        String shipCompanyId = shipLocation.getCompany().getId();
        return locationRepository.findAll("SELECT ID FROM MAS_LOCATION WHERE " +
                "((COMPANY_ID = '"+ shipCompanyId +"' AND USAGE_ID IN ('1', '4')) OR (COMPANY_ID != '"+ shipCompanyId +"' AND USAGE_ID = '"+ shipLocation.getUsage().getId() +"')) " +
                "AND ID != '"+ shipLocation.getId() +"'");
    }

    public List externalCanDumpReceiptLocation(SimpleRequest request) {
        Location location = locationRepository.findOne(request.getJO().getString("id"));
        String shipCompanyId = location.getCompany().getId();
        return locationRepository.findAll("SELECT ID FROM MAS_LOCATION WHERE " +
                "((COMPANY_ID = '"+ shipCompanyId +"' AND USAGE_ID IN ('1', '4')) OR (COMPANY_ID != '"+ shipCompanyId +"' AND USAGE_ID = '"+ location.getUsage().getId() +"')) " +
                "AND ID != '"+ location.getId() +"'");
    }


    // 批量补货 - 调拨
    public CrossCompanyTransferNew batchDumpCrossSave(SimpleRequest request) {
        Map getM = request.getMap();
        boolean flag = (boolean) getM.get("flag");
        CrossCompanyTransferNew transfer = Tools.map(getM.get("crossNew"), CrossCompanyTransferNew.class);
        SpringManager.getBean(MapUtil.class).refresh(transfer);
        transfer.setState("sent");
        List<PartyRole> suppliers = new ArrayList<>();
        if (!(flag && !(boolean) getM.get("checkContract"))) formatTransferSupplier(suppliers, (JSONArray) getM.get("suppliers"));
        transfer.setUserId(userRepository.findOne(JpaDsl.toCriteriaByEq("person.id", transfer.getCreateUid().getId())).get().getId() + "");
        transfer = crossCompanyTransferRepository.saveAndFlush(transfer);

        // 找批次
        this.batchDumpFindInventoryBatch(transfer, suppliers, (boolean) getM.get("flag"), (boolean) getM.get("checkContract"));

        // 减少可用数、转入制单数量、未达账
        if (!transfer.getCrossCompanyTransferItems().isEmpty()) changeUseQty(transfer, 1);

        if (transfer.getCrossCompanyTransferItems().isEmpty()) {
            crossCompanyTransferRepository.delete(transfer);
            return new CrossCompanyTransferNew();
        }



        // 异常数据在找批次时剔除，二次保存
        crossCompanyTransferRepository.save(transfer);

        // 检查批次
//        checkInventoryBatch(transfer);

        return transfer;
    }

    // 格式化数据 - 获取批次需要
    private void formatTransferSupplier(List<PartyRole> suppliers, JSONArray supplierArray) {
        supplierArray.forEach(supplier -> {
            suppliers.add(Tools.map(supplier, PartyRole.class));
        });
    }

    /**
     * 功能: 找批次 - 批量补货专用
     * @param transfer
     * @param suppliers
     * @param flag 调拨范围内是否获取全部供应商
     * @param checkContract 赋能 ---> 非赋能 判断合同
     */
    public void batchDumpFindInventoryBatch(CrossCompanyTransferNew transfer, List<PartyRole> suppliers, boolean flag, boolean checkContract) {
        Dept dept = getDept(transfer);

        List itemIds = new ArrayList();
        transfer.getCrossCompanyTransferItems().stream().forEach(Item -> new BatchMethod<Batch>() {
            @Override
            public Iterable<Batch> wrap() {
                // 批次先经销后代销
                List<InventoryBatch> inventories;
                if (flag && !checkContract) {

                    inventories = inventoryService.findInventoryBatchForSaleOrder(transfer.getCompany(), dept, Item.getProduct());
                } else {
                    if (suppliers.size() == 0) throw new RuntimeException("未找到可调拨供应商");

                    List<String> supplierIds = suppliers.stream().distinct().map(singleSupplier -> {return singleSupplier.getId();}).collect(Collectors.toList());
                    if (checkContract) { // 剔除内部供应商
                        inventories = SpringManager.getBean(InventoryBatchRepository.class).findInvenBaForSaleOrderNotInnerSupplier(transfer.getCompany(), dept, supplierIds, Item.getProduct());
                    } else {
                        inventories = SpringManager.getBean(InventoryBatchRepository.class).findInventoryBatchForSaleOrder(transfer.getCompany(), dept, supplierIds, Item.getProduct());
                    }
                    // 测试代码 - 暂时未进行测试，勿删
//                    List<PartyRole> supplierIdstest = suppliers.stream().peek(partyRole -> {partyRole.getId();}).collect(Collectors.toList());

                }
                return inventoryService.wrapBatch(inventories, Item.getUom(), inventory -> inventory.getBalanceQty() - inventory.getFrostQty());
            }

            @Override
            public void succeed(Batch batch, double increment) {
                //添加调拨批次
                TransferBatch transferBatch = new TransferBatch();
                transferBatch.setCrossCompanyTransfer(Item.getCrossCompanyTransfer());
                transferBatch.setCompanyTransferItem(Item);
                transferBatch.setProduct(Item.getProduct());
                InventoryBatch inventoryBatch = (InventoryBatch) batch.getEntity();
                transferBatch.setInventoryBatch(inventoryBatch);
                transferBatch.setUom(Item.getUom());//设置单位
                transferBatch.setProductQty(increment);//设置调拨数量
                transferBatchRepository.saveAndFlush(transferBatch);
                /**冻结批次**/
                changeFrostQty(inventoryBatch, Item.getUom(), abs(increment), transfer.getCompany(),
                        transfer.getInnerBusinessType(), transfer.getId(), String.valueOf(Item.getId()), "跨公司调拨保存");

            }

            @Override
            public void error(double surplus) {
                String productId = Item.getProduct().getId();
                List<BatchOfFrozen> batchOfFrozens = invoke("acc.inventoryService.findByCurrentNumber",
                        MapUtil.mapper("sourceBusinessType", transfer.getInnerBusinessType(), "orderNumber", transfer.getId(), "productId", productId));

                batchOfFrozens.forEach(batchOfFrozen -> { // 使用批次明细加回数据
                    InventoryBatch inventoryBatch = inventoryBatchRepository.findOne(batchOfFrozen.getBatchId());
                    changeFrostQty(inventoryBatch, Item.getUom(), -1 * abs(batchOfFrozen.getChangeQty()), transfer.getCompany(),
                            transfer.getInnerBusinessType(), transfer.getId(), String.valueOf(Item.getId()), "批量补货 - 调拨异常还原");
                });

                // 删除错误批次商品
                List<TransferBatch> transferBatchs = transferBatchRepository.findCanDelteTransferBatch(transfer.getId(), Item.getId());
                transferBatchs.forEach(crossBatch -> {
                    transferBatchRepository.delete(crossBatch);
                });

                // 异常数据添加
                itemIds.add(Item.getId());

//                throw new RuntimeException("商品：["+Item.getProduct().getId()+"]" + Item.getProduct().getName() + " 价值库存数量少 " + surplus + Item.getUom().getName() + "！");
                String message = "库存不足！";
                SpringManager.getBean(BatchDumpTransferService.class).updateErrorReason(
                        MapUtil.mapper("NOTE", message, "BATCH_DUMP_ID", transfer.getSource(), "RECEIPT_LOCATION_ID", transfer.getReceiptLocation().getId(), "PRODUCT_ID", productId)
                );
            }
        }.execute(abs(Item.getProductSum())));

        if (!itemIds.isEmpty()) this.removeErrorItem(transfer.getCrossCompanyTransferItems(), itemIds);
    }

    private static Dept getDept(CrossCompanyTransferNew transfer) {
        Dept dept = transfer.getShipLocation().getDept();
        if (dept == null) {
            throw new RuntimeException("调拨发货仓所属部门为空！");
        }
        if (!(dept.existDeptType(DeptEnum.RETAIL) || dept.existDeptType(DeptEnum.SALE))) {
            throw new RuntimeException("调拨发货仓所属部门为非销售部门！");
        }
        if (!dept.existDeptType(DeptEnum.PURCHASE)) {
            throw new RuntimeException("调拨发货仓所属部门为非采购部门！");
        }
        return dept;
    }

    // 迭代删除错误数据
    private void removeErrorItem(Set<CrossCompanyTransferItemNew> items, List removeItemIds) {
        Iterator<CrossCompanyTransferItemNew> iCrossItem = items.iterator();
        while (iCrossItem.hasNext()) {
            CrossCompanyTransferItemNew item = iCrossItem.next();
            if (removeItemIds.contains(item.getId())) iCrossItem.remove();
        }
    }

    /**
     * 功能: 找批次
     * @param transfer
     * @param supplierIds
     * @param flag 调拨范围内是否获取全部供应商
     * @param checkContract 赋能 ---> 非赋能 判断合同
     */
    public void findInventoryBatch(CrossCompanyTransferNew transfer, List<String> supplierIds, boolean flag, boolean checkContract) {
        Dept dept = getDept(transfer);
        transfer.getCrossCompanyTransferItems().stream().forEach(Item -> new BatchMethod<Batch>() {
            @Override
            public Iterable<Batch> wrap() {
                // 批次先经销后代销
                List<InventoryBatch> inventories;
                if (flag && !checkContract) {
                    inventories = inventoryService.findInventoryBatchForSaleOrder(transfer.getCompany(), dept, Item.getProduct());
                } else {
                    if (supplierIds.size() == 0) throw new RuntimeException("未找到可调拨供应商");

//                    List<String> supplierIds = suppliers.stream().distinct().map(singleSupplier -> {return singleSupplier.getId();}).collect(Collectors.toList());
                    if (checkContract) { // 剔除内部供应商
                        inventories = SpringManager.getBean(InventoryBatchRepository.class).findInvenBaForSaleOrderNotInnerSupplier(transfer.getCompany(), dept, supplierIds, Item.getProduct());
                    } else {
                        inventories = SpringManager.getBean(InventoryBatchRepository.class).findInventoryBatchForSaleOrder(transfer.getCompany(), dept, supplierIds, Item.getProduct());
                    }
                    // 测试代码
//                    List<PartyRole> supplierIdstest = suppliers.stream().peek(partyRole -> {partyRole.getId();}).collect(Collectors.toList());

                }
                return inventoryService.wrapBatch(inventories, Item.getUom(), inventory -> inventory.getBalanceQty() - inventory.getFrostQty());
            }

            @Override
            public void succeed(Batch batch, double increment) {
                //添加调拨批次
                TransferBatch transferBatch = new TransferBatch();
                transferBatch.setCrossCompanyTransfer(Item.getCrossCompanyTransfer());
                transferBatch.setCompanyTransferItem(Item);
                transferBatch.setProduct(Item.getProduct());
                InventoryBatch inventoryBatch = (InventoryBatch) batch.getEntity();
                transferBatch.setInventoryBatch(inventoryBatch);
                transferBatch.setUom(Item.getUom());//设置单位
                transferBatch.setProductQty(increment);//设置调拨数量
                transferBatchRepository.saveAndFlush(transferBatch);
                /**冻结批次**/
                changeFrostQty(inventoryBatch, Item.getUom(), abs(increment), transfer.getCompany(),
                        transfer.getInnerBusinessType(), transfer.getId(), String.valueOf(Item.getId()), "跨公司调拨保存");

            }

            @Override
            public void error(double surplus) {
                throw new RuntimeException("商品：["+Item.getProduct().getId()+"]" + Item.getProduct().getName() + " 价值库存数量少 " + surplus + Item.getUom().getName() + "！");
            }
        }.execute(abs(Item.getProductSum())));
    }

    public void changeUseQty(CrossCompanyTransferNew transferNew, int typeValue) {
        List itemIds = new ArrayList();
        transferNew.getCrossCompanyTransferItems().forEach(item-> {
            Location shipLocation = item.getCrossCompanyTransfer().getShipLocation();
            String innerBusi = item.getCrossCompanyTransfer().getInnerBusinessType();
            String itemId = String.valueOf(item.getId());
            try {
                // 减少商品库存账
                productAccountService.setProductAvailable(item.getProduct(), shipLocation,
                        item.getUom(), -1 * item.getProductSum(), innerBusi, transferNew.getId(),
                        itemId, "跨公司调拨保存", transferNew.getCompany());
            } catch (Exception e) {
                if (transferNew.getSourceBusinessType().equals("BatchDump")) { // 批量补货异常捕捉
                    SpringManager.getBean(BatchDumpTransferService.class).updateErrorReason(
                            MapUtil.mapper("NOTE", e.getMessage(), "BATCH_DUMP_ID", transferNew.getSource(), "RECEIPT_LOCATION_ID", transferNew.getReceiptLocation().getId(), "PRODUCT_ID", item.getProduct().getId())
                    );

                    productAccountService.setProductAvailable(item.getProduct(), shipLocation,
                            item.getUom(), item.getProductSum(), innerBusi, transferNew.getId(),
                            itemId, "批量补货 - 跨公司异常", transferNew.getCompany());

                    // 删除批次
                    List<TransferBatch> transferBatchs = transferBatchRepository.findCanDelteTransferBatch(transferNew.getId(), item.getId());
                    transferBatchs.forEach(crossBatch -> {

                        /**冻结批次还原**/
                        changeFrostQty(crossBatch.getInventoryBatch(), item.getUom(), -1 * abs(crossBatch.getProductQty()), transferNew.getCompany(),
                                transferNew.getInnerBusinessType(), transferNew.getId(), String.valueOf(item.getId()), "批量补货 - 跨公司异常还原");

                        transferBatchRepository.delete(crossBatch);
                    });

                    itemIds.add(itemId);
                    e.printStackTrace();
                    return; // 跳过一次循环
                } else {
                    throw new RuntimeException(e.getMessage());
                }
            }

            // 转入制单数量
            productAccountService.setProductTransferInBilling(item.getProduct(),
                    transferNew.getReceiptLocation(), item.getUom(), typeValue * item.getProductSum(),
                    transferNew.getReceiptLocation().getCompany());

            // 未达账
            this.saveDepositInTransit(transferNew, item);
        });

        this.removeErrorItem(transferNew.getCrossCompanyTransferItems(), itemIds);
    }

    public void checkInventoryBatch(CrossCompanyTransferNew crossCompanyTransferNew) {
        crossCompanyTransferNew.getCrossCompanyTransferItems().forEach(item-> {
            List<TransferBatch> transferBatches = transferBatchRepository.findAll(JpaDsl.toCriteriaByEq("companyTransferItem.id", item.getId()));
            if (transferBatches.size() == 0) throw new RuntimeException("未找到调拨批次");
        });
    }


    // 剔除不能调拨批次
    public List<InventoryBatch> batchNotCondiInventoryBatch(Location shipLocation, Location receiptLocation, List<InventoryBatch> inventories) {
        String shipOperation = this.queryOperationModel(shipLocation.getCompany());
        String receptionOperation = this.queryOperationModel(receiptLocation.getCompany());
        String export = "empower".equals(shipOperation)?"001073":"subsidiary".equals(shipOperation)?"001661":"001072";
        String reception = "empower".equals(receptionOperation)?"001073":"subsidiary".equals(receptionOperation)?"001661":"001072";
        List<String> innerSupplier = partyRoleRepository.findAllInnerSupplier().stream().map(m -> m.getId()).collect(Collectors.toList());
        if ("001073".equals(export) && !"001073".equals(reception)) {
            return inventories.stream().filter(inventoryBatch -> !("distribution".equals(inventoryBatch.getCooperation().getId()) && !innerSupplier.contains(inventoryBatch.getSupplier().getId()))).collect(Collectors.toList());
        }
        return inventories;
    }

    public List<InventoryBatch> sortBatch(List<InventoryBatch> inventories) {
        List<InventoryBatch> distribution = inventories.stream().filter(e -> e.getCooperation().getId().equals("distribution")).collect(Collectors.toList());
        List<InventoryBatch> consignment = inventories.stream().filter(e -> e.getCooperation().getId().equals("consignment")).collect(Collectors.toList());
        List<InventoryBatch> batchList = new ArrayList<>();
        batchList.addAll(distribution);
        batchList.addAll(consignment);
        return batchList;
    }

    /**
     * 未达帐
     **/
    private void saveDepositInTransit(CrossCompanyTransferNew transfer, CrossCompanyTransferItemNew item) {
        DepositInTransitService depositInTransitService = SpringManager.getBean(DepositInTransitService.class);
//        transfer.getCrossCompanyTransferItems().forEach(item -> {
            double occurQty = productAccountService.computeQtyUnit(transfer.getCompany(), item.getProduct(), item.getUom(), item.getProductSum());
            depositInTransitService.save(transfer.getShipLocation().getCompany(), transfer.getShipLocation(), transfer.getReceiptLocation().getDepot().getDept(), transfer.getInnerBusinessType(), transfer.getInnerBusinessKey(),
                    item.getId(), item.getProduct(), occurQty, "发货");
            depositInTransitService.save(transfer.getReceiptLocation().getCompany(), transfer.getReceiptLocation(), transfer.getShipLocation().getDepot().getDept(), transfer.getInnerBusinessType(), transfer.getInnerBusinessKey(),
                    item.getId(), item.getProduct(), occurQty, "收货");
//        });
    }



    private CrossCompanyTransferNew update(SimpleRequest request) {
        CrossCompanyTransferNew transfer = request.getO(CrossCompanyTransferNew.class);
        storeService.judgeFCKBJ(transfer.getReceiptLocation());
        storeService.judgeFCKBJ(transfer.getShipLocation());
        transfer.setState("sent");

        // 还原库存可用数，批次冻结数
        CrossCompanyTransferNew companyTransfer = crossCompanyTransferRepository.findOne(transfer.getId());
        updateProductAvailableAndBatch(companyTransfer,"跨公司调拨还原");

        // 删除批次，必须放在 updateProductAvailableAndBatch 语句后
        transferBatchRepository.deleteAll(transferBatchRepository.findByTransferId(transfer.getId()));

        transfer = crossCompanyTransferRepository.saveAndFlush(transfer);

        // 检查主数据是否过期
        this.approveCheckPreData(transfer);

        // 冻结批次
        this.freezeBatch(transfer);

        // 减少可用数、增加收货仓转入制单数量、写入双方未达账
        this.reduceChangeStock(transfer);

        // 判断批次
//        checkInventoryBatch(transfer);
        return transfer;
    }

    /**
     * 删除
     *
     * @param request
     * @return
     */
    private CrossCompanyTransferNew delete(SimpleRequest request) {
        CrossCompanyTransferNew transfer = request.getO(CrossCompanyTransferNew.class);
        /**还原库存可用数、批次冻结数、增加转入制单数量、删除未达账*/
        updateProductAvailableAndBatch(crossCompanyTransferRepository.findOne(transfer.getId()),"跨公司调拨还原");
        transfer.setState("delete");
        crossCompanyTransferRepository.saveAndFlush(transfer);
        return new CrossCompanyTransferNew();
    }

    /**
     *终止
     * @param request
     */
    private CrossCompanyTransferNew termination(SimpleRequest request) {
        CrossCompanyTransferNew transfer = request.getO(CrossCompanyTransferNew.class);
        if (!this.canTermination(transfer.getId())) throw new RuntimeException("单据状态已变更，请刷新！");
        transfer.setStopUid(request.getPerson());
        transfer.setStopDate(new Date());

        CrossCompanyTransferNew transferNew = crossCompanyTransferRepository.findOne(transfer.getId());
        if ("done".equals(transferNew.getState())) throw new RuntimeException("调拨单已完成，无法终止");
        boolean flag = false;
        for (CrossCompanyTransferItemNew itemNew : transferNew.getCrossCompanyTransferItems()) {
            if (itemNew.getProductSum() != itemNew.getShipNum()) flag = true;
        }
        if (!flag) throw new RuntimeException("商品已全部发货，无法终止");

        //单据状态 && 设置终止数量
        String state = "done";
        for (CrossCompanyTransferItemNew itemNew:transfer.getCrossCompanyTransferItems()) {
            //终止数量    =   调拨数量  -  发货数量
            double canTerminationQty = itemNew.getProductSum()-itemNew.getShipNum() - itemNew.getFinishSum();
            //调拨数   =    已收货数  +  终止数？  完成：审核
            if (itemNew.getProductSum() != itemNew.getArrivalSum() + (canTerminationQty == 0?itemNew.getFinishSum():itemNew.getFinishSum() + canTerminationQty)){
                state = "approve";
            }
            if (canTerminationQty <= 0) continue;
            itemNew.setFinishSum(itemNew.getFinishSum() + canTerminationQty);

            double changeQty = Math.abs(canTerminationQty);
            /**增加商品可用数*/
            productAccountService.setProductAvailable(itemNew.getProduct(), transfer.getShipLocation(),
                    itemNew.getUom(), changeQty, transfer.getInnerBusinessType(), transfer.getId(),
                    String.valueOf(itemNew.getId()), "新跨公司调拨终止", transfer.getCompany());
            /**减少转入制单数*/
            productAccountService.setProductTransferInBilling(itemNew.getProduct(),
                    transfer.getReceiptLocation(), itemNew.getUom(), -1 * changeQty,
                    transfer.getReceiptLocation().getCompany());

            /**减少商品批次的冻结数量*/
            List<TransferBatch> transferBatchList = transferBatchRepository.findByItem(itemNew.getId());
            for (TransferBatch transferBatch : transferBatchList) {
                if (changeQty == 0) break;
                //批次可终止数量
                double qty = transferBatch.getProductQty() - transferBatch.getShipQty() - transferBatch.getFinishSum();
                if (qty <= 0) continue;
                if (changeQty >= qty) {
                    transferBatch.setFinishSum(transferBatch.getFinishSum() + qty);
                    changeFrostQty(transferBatch.getInventoryBatch(), transferBatch.getUom(), -1 * qty, transfer.getCompany(), transfer.getInnerBusinessType(), transfer.getId(),
                            String.valueOf(itemNew.getId()), "新跨公司调拨终止");
                    changeQty -= qty;
                }else {
                    transferBatch.setFinishSum(transferBatch.getFinishSum() + changeQty);
                    changeFrostQty(transferBatch.getInventoryBatch(), transferBatch.getUom(), -1 * changeQty, transfer.getCompany(), transfer.getInnerBusinessType(), transfer.getId(),
                            String.valueOf(itemNew.getId()), "新跨公司调拨终止");
                    changeQty = 0;
                }
            }

            // 减少安全库存缺口分配数量
            this.sendUpdateGapAssignedQty(transfer.getSpecialDocumentsType(), itemNew, -1 * itemNew.getFinishSum());

            // 修改安全库存 - 要货扩展表的取消数量
            this.stopSendUpdateRequireExpandAssignedQty(transfer.getId(), transfer.getSpecialDocumentsType(), itemNew);

            // 要货批量转储 - 终止要货分配数、要货扩展表、要货制单数量
            this.terminationNoticRequireAndRequireExpand(transfer);
        }

        /**取消交货单*/
        JSONObject tempJson = new JSONObject();
        tempJson.put("operation","deliver");
        List<Map> items = this.makeupPick(tempJson, transfer);
        if (items.size() == 0) return transfer;
        tempJson.put("items", items);
        invoke("stock.pick.dumpCancel", tempJson);

        /**删除未达帐**/
        transfer.getCrossCompanyTransferItems().forEach(item -> {
            depositInTransitService.delete(transfer.getInnerBusinessType(), transfer.getInnerBusinessKey(),
                    item.getId(), transfer.getShipLocation());
            if (item.getProductSum() == item.getArrivalSum()+item.getFinishSum()) {
                depositInTransitService.delete(transfer.getInnerBusinessType(), transfer.getInnerBusinessKey(),
                        item.getId(), transfer.getReceiptLocation());
            }

        });


        transfer.setState(state);
        CrossCompanyTransferNew crossCompanyTransfer = crossCompanyTransferRepository.saveAndFlush(transfer);

        // 要货转储
        Map<String, String> param = new HashMap<>();
        param.put("id", crossCompanyTransfer.getId());
        param.put("innerBusinessType", crossCompanyTransfer.getInnerBusinessType());

        // 旧 - 要货转储要货明细数量、扩展数量更改，新的逻辑上线一段时间后删除
//        invoke("stock.autoProductRequireDumpService.requireExpandDumpCacel", param);

        return crossCompanyTransfer;
    }

    private boolean canTermination(String crossId) {
        String sql = "" +
                "SELECT 1 " +
                "  FROM CROSS_COMPANY_TRAN_NEW A, CROSS_COMPANY_TRAN_ITEM_NEW B, " +
                "       (SELECT ORIGIN, ORIGIN_LINE, PRODUCT_ID, SUM(PRODUCT_UOM_QTY) QTY_DONE " +
                "           FROM STOCK_PICK J, STOCK_PICK_ITEM K " +
                "          WHERE J.ID = K.PICK_ID " +
                "            AND OPERATION = 'deliver' " +
                "            AND J.STATE = 'confirmed' " +
                "          GROUP BY ORIGIN, ORIGIN_LINE, PRODUCT_ID) C " +
                " WHERE A.ID = B.TRANSFER_ID AND A.ID = C.ORIGIN " +
                "   AND B.ID = C.ORIGIN_LINE " +
                "   AND A.ID = '"+ crossId +"' " +
                "   AND B.PRODUCT_SUM - SHIP_SUM - FINISH_SUM != C.QTY_DONE  ";
        List nTerminations = crossCompanyTransferRepository.findAll(sql);
        if (nTerminations.size() > 0) return false;

        sql = "" +
                "SELECT 1  " +
                "  FROM CROSS_COMPANY_TRAN_NEW A, CROSS_COMPANY_TRAN_ITEM_NEW B,  " +
                "       (SELECT ORIGIN, ORIGIN_LINE, PRODUCT_ID, SUM(QTY_DONE) QTY_DONE  " +
                "           FROM STOCK_PICK J, STOCK_PICK_ITEM K  " +
                "          WHERE J.ID = K.PICK_ID  " +
                "            AND OPERATION = 'deliver'  " +
                "            AND J.STATE = 'done' AND WITHDRAW_UID IS NULL " +
                "          GROUP BY ORIGIN, ORIGIN_LINE, PRODUCT_ID) C  " +
                " WHERE A.ID = B.TRANSFER_ID AND A.ID = C.ORIGIN  " +
                "   AND B.ID = C.ORIGIN_LINE " +
                "   AND A.ID = '"+ crossId +"' " +
                "   AND SHIP_SUM != C.QTY_DONE ";
        nTerminations = crossCompanyTransferRepository.findAll(sql);
        if (nTerminations.size() > 0) return false;
        return true;
    }

    /**
     * 收货在途/发货在途
     */
    private void setNumber(CrossCompanyTransferNew transfer,String method) {
        // A转储发货在途 ，B转储收货在途
        transfer.getCrossCompanyTransferItems().forEach(orderItem -> {
            // 发货在途
            productAccountService.setProductTransferIssue(orderItem.getProduct(),
                    transfer.getShipLocation(), //发货仓库
                    orderItem.getUom(),
                    "termination".equals(method)?-1*orderItem.getFinishSum():orderItem.getProductSum(),// 发货在途改变的数量(减去终止数)
                    orderItem.getCrossCompanyTransfer().getShipLocation().getCompany());

            // 收货在途
            productAccountService.setProductTransferReceive(orderItem.getProduct(),
                    transfer.getReceiptLocation(),
                    orderItem.getUom(),
                    "termination".equals(method)?-1*orderItem.getFinishSum():orderItem.getProductSum(),
                    orderItem.getCrossCompanyTransfer().getReceiptLocation().getCompany());
        });
    }

    /**
     * 拼接交货信息
     * @param tempJson
     * @param order
     * @return
     */
    private List<Map> makeupPick(JSONObject tempJson, CrossCompanyTransferNew order) {
        tempJson.put("id", order.getId());
        tempJson.put("innerBusinessType", order.getInnerBusinessType());
        List<Map> items = order.getCrossCompanyTransferItems().stream().filter(itemNew -> itemNew.getProductSum() != itemNew.getShipNum())
                .map(itemNew -> {
                    Map pickItem = new HashMap();
                    pickItem.put("id", itemNew.getId());
                    pickItem.put("cancelQty", itemNew.getFinishSum());
                    return pickItem;
                }).collect(Collectors.toList());
        return items;
    }

    /**
     * 交货单发货回写数据到调拨单
     */
    @Listener(topic = "event:stock.pick.delivery")
    private void willWrite(SimpleRequest request) {
        JSONObject param = request.getJO();
        if (!param.getString("originBusinessType").equals(CrossCompanyTransferNew.class.getSimpleName())) return;
        String pickId = param.getString("pickId");
        if (pickId == null) return;
        Pick pick = pickRepository.findOne(pickId);
        CrossCompanyTransferNew transferNew = crossCompanyTransferRepository.findOne(pick.getOrigin());
        if (transferNew == null) return;

        /**回写交货数量到调拨单*/
        changeCrossQty(pick,transferNew);

        if (!"deliver".equals(pick.getOperation())) {//收货
            /**减少发/收货在途*/
            changeQtyByPick(pick,transferNew,-1);
            /**生成凭证*/
//            this.createVoucher(pick,transferNew);
        }else {
            /**减少转入制单数*/
            changeTransferInBillingByPick(pick,-1);
            /**增加发/收货在途*/
            changeQtyByPick(pick,transferNew,1);
            /**发货时写调拨批次表的发货数量，用于终止*/
            changeTransferBatchQty(pick);
            /**生成收货单*/
            this.createReceiptPick(request);
        }

        /**回写调拨单据状态*/
        changeCrossState(transferNew);

       /* Map requireDumpParam = new HashMap();
        requireDumpParam.put("pickId", pickId);
        invoke("stock.autoProductRequireDumpService.receiptAndDelivery", requireDumpParam);*/

        // 准备凭证数据
        this.readyVoucherData(pick.getOperation(), pickId, transferNew.getId());


    }

    // 准备凭证数据
    private void readyVoucherData(String operation, String pickId, String crossId) {
        if ("deliver".equals(operation)) return;
        JSONObject condi = new JSONObject();
        condi.put("pickId", pickId);
        condi.put("crossId", crossId);
        SpringManager.getBean(OutboxSubscriberService.class)
                .commonSendRequest("local:crossCompanyTransferNewService.writeVoucherOutbox", crossId, condi);
    }

    @OutboxSubscriber(id="local:crossCompanyTransferNewService.writeVoucherOutbox", name="调拨写入凭证")
    private void writeVoucherOutbox(OutboxPayloadWrapper outboxPayloadWrapper) {
        this.createVoucher(JSONObject.parseObject(outboxPayloadWrapper.getPayload()));
    }

    /**
     * 申请
     *
     * @param request
     * @return
     */
    private CrossCompanyTransferNew apply(SimpleRequest request) {
        CrossCompanyTransferNew transfer = request.getO(CrossCompanyTransferNew.class);
        transfer.setState("apply");

        transfer.setApplyUid(this.getPerson(request));
        transfer.setDateApply(new Date());
        transfer = crossCompanyTransferRepository.saveAndFlush(transfer);
        return transfer;
    }

    /**
     * 驳回申请(退回)
     *
     * @param request
     * @return
     */
    private CrossCompanyTransferNew reject(SimpleRequest request) {
        CrossCompanyTransferNew transfer = request.getO(CrossCompanyTransferNew.class);
        transfer.setState("sent");
        if (transfer.getApproveUid() == null) transfer.setApproveUid(this.getPerson(request));
        transfer.setDateApprove(new Date());
        transfer = crossCompanyTransferRepository.saveAndFlush(transfer);

        return transfer;
    }

    /**
     * 审核
     *
     * @param request
     * @return
     */
    private CrossCompanyTransferNew approve(SimpleRequest request) {
        CrossCompanyTransferNew transfer = request.getO(CrossCompanyTransferNew.class);
        transfer.setState("approve");
        if (transfer.getApproveUid() == null) transfer.setApproveUid(this.getPerson(request));
        transfer.setDateApprove(new Date());
        User user = userRepository.findAll(JpaDsl.toCriteriaByEq("person.id", transfer.getApproveUid().getId())).stream().findFirst().orElse(null);
        if (user != null) transfer.setUserId(user.getId() + "");

        // 检查主数据是否过期
        this.approveCheckPreData(transfer);

        transfer = crossCompanyTransferRepository.saveAndFlush(transfer);

        // 修改扩展表
        this.updateOtherTable(transfer);

        //创建交货单
        this.createPickOrder(request);

        return transfer;
    }

    private void approveCheckPreData(CrossCompanyTransferNew cross) {
        String export = invoke("scm.transferProductService.accordLCompanyChangeOperation", MapUtil.mapper("id", cross.getShipLocation().getId()));
        String reception = invoke("scm.transferProductService.accordLCompanyChangeOperation", MapUtil.mapper("id", cross.getReceiptLocation().getId()));
        List<TransferProduct>  transferProducts = transferProductRepository.findByALL(export, reception);
        TransferProduct tProduct = transferProducts.stream().filter(transferProduct -> transferProduct.getSupplier() == null).findFirst().orElse(new TransferProduct());
        Set<String> suppliers = tProduct == null?transferProducts.stream().map(transferProduct -> {return transferProduct.getSupplier().getId();}).collect(Collectors.toSet()):new HashSet<>();
        long receiptCompanyPartyId = cross.getReceiptLocation().getCompany().getParty().getId();
        String shipCompanyId = cross.getShipLocation().getCompany().getId();
        transferBatchRepository.findByTransferId(cross.getId()).forEach(transferBatch -> {
            // 判断供应商
            if (tProduct == null) {
                String supplierId = transferBatch.getInventoryBatch().getSupplier().getId();
                if (!suppliers.contains(supplierId)) {
                    throw new RuntimeException("调拨范围设置已过期, 供应商: " + supplierId);
                }
            }

            // 判断合同
            boolean existsContranct = this.judgeInventoryContract(export, reception, transferBatch.getInventoryBatch(), receiptCompanyPartyId, shipCompanyId);
            if (!existsContranct) throw new RuntimeException("请检查采购合同、平台协议是否过期");
        });

    }

    /**
     * 更新商品库存可用数，批次表冻结数量
     *
     * @param cross
     * @param note
     */
    private void updateProductAvailableAndBatch(CrossCompanyTransferNew cross, String note) {
        cross.getCrossCompanyTransferItems().forEach(crossItem -> {

            double changeQty = Math.abs(crossItem.getProductSum());
            if (LogicalUtil.notIn(crossItem.getProduct().getType(), "aut")) {
                // 增加商品可用数
                productAccountService.setProductAvailable(crossItem.getProduct(), cross.getShipLocation(),
                        crossItem.getUom(), changeQty, cross.getInnerBusinessType(), cross.getId(),
                        String.valueOf(crossItem.getId()), note, cross.getCompany());
            }

            // 减少商品价值（商品批次） 的冻结数量
            List<TransferBatch> transferBatchList = transferBatchRepository.findByItem(crossItem.getId());
            transferBatchList.forEach(transferBatch -> {
                double qty = -1 * transferBatch.getProductQty();
                InventoryBatch inventoryBatch = inventoryBatchRepository.findOne(transferBatch.getInventoryBatch().getId());
                changeFrostQty(inventoryBatch, transferBatch.getUom(), qty, cross.getCompany(), cross.getInnerBusinessType(), cross.getId(),
                        String.valueOf(crossItem.getId()), note);
            });

            // 删除未达账
            depositInTransitService.delete(cross.getInnerBusinessType(), cross.getInnerBusinessKey(),
                    crossItem.getId(), cross.getShipLocation());
            depositInTransitService.delete(cross.getInnerBusinessType(), cross.getInnerBusinessKey(),
                    crossItem.getId(), cross.getReceiptLocation());

            // 减少转入制单数量
            productAccountService.setProductTransferInBilling(crossItem.getProduct(), cross.getReceiptLocation(), crossItem.getUom(), -1 * crossItem.getProductSum(), cross.getReceiptLocation().getCompany());


        });
    }

    public void changeFrostQty(InventoryBatch inventoryBatch, ProductUom uom, double changeQty,
                               PartyRole company, String sourceBusinessType, String orderNumber,
                               String orderSerialNumber, String remarks) {
        double frostQty = uom.computeQty(changeQty, inventoryBatch.getUom(), true);
        if (changeQty > 0 || (changeQty < 0 && inventoryBatch.getFrostQty() >= abs(frostQty))) {
            inventoryService.changeFrostQty(inventoryBatch, uom, changeQty, company, sourceBusinessType, orderNumber, orderSerialNumber, remarks);
            return;
        }

        /**还原冻结数量时，数量不足（变价或其它原因）**/
        new BatchMethod<Batch>() {
            @Override
            public Iterable<Batch> wrap() {
                List<Long> batchNumbers = new ArrayList<>();
                batchNumbers.add(inventoryBatch.getBatchNumber());
                List<InventoryBatch> inventories = inventoryService.findAllByBatchNumber(batchNumbers, inventory -> inventory.getFrostQty());
                return inventoryService.wrapBatch(inventories, inventoryBatch.getUom(), inventory -> inventory.getFrostQty());
            }

            @Override
            public void succeed(Batch batch, double increment) {
                InventoryBatch inventoryBatch = (InventoryBatch) batch.getEntity();
                inventoryService.changeFrostQty(inventoryBatch, inventoryBatch.getUom(), -1 * increment, company, sourceBusinessType, orderNumber, orderSerialNumber, remarks);
            }

            @Override
            public void error(double surplus) {
                throw new RuntimeException("商品：[" + inventoryBatch.getProduct().getId() + "]" + inventoryBatch.getProduct().getName() + " 价值库存冻结数量少 " + surplus + inventoryBatch.getUom().getName() + "！");
            }
        }.execute(abs(frostQty));
    }


    private List<Map> setData(List<Stock> stockList, List<InventoryBatch> inventoryBatchList) {
        List<Map> returnData = new ArrayList<>();
        stockList.forEach(stock -> {
            List<InventoryBatch> meetCondiInventBs = inventoryBatchList.stream().filter(e->e.getProduct().getId().equals(stock.getProduct().getId())).collect(Collectors.toList());
            if (meetCondiInventBs.isEmpty()) return;

            double stockQty = stock.getUsableQty() - stock.getFrozenQty();
            double inventoryBatchQty = 0;
            ProductUom productUom = productUomRepository.findByProductId(stock.getProduct().getId());
            ProductUom inventoryBatchUom = new ProductUom();
            Set<String> suppliers = new HashSet<>();
            for (InventoryBatch inventoryBatch : meetCondiInventBs) {
                inventoryBatchQty += (inventoryBatch.getBalanceQty() - inventoryBatch.getFrostQty());
                inventoryBatchUom = inventoryBatch.getUom();
                suppliers.add(inventoryBatch.getSupplier().getId());
            }

            //可调拨数取最小值
            double productSumQty = stockQty > inventoryBatchQty?inventoryBatchQty:stockQty;
            if (productSumQty < 0) productSumQty = 0;

            double batchQty = inventoryBatchUom.computeQty(productSumQty, productUom,true);
            int batchQtyI = (int) batchQty;
            double batchQtyD =  batchQty - batchQtyI;

            Map map = new HashMap<>();
            if (batchQtyD > 0) {
                map.put("uom",inventoryBatchUom);
                map.put("factor", inventoryBatchUom.getFactor());
                map.put("product",stock.getProduct());
                map.put("usableQty", stock.getUsableQty());
                map.put("batchQty", inventoryBatchQty);
                map.put("stockUsableQty", stockQty);
                map.put("productSumQty", productSumQty);
                map.put("suppliers", suppliers);
            } else {
                map.put("uom", productUom);
                map.put("factor", Arith.round(1 / productUom.getFactor(), Arith.computeDecimalPlaces(productUom.getRounding())));
                map.put("product", stock.getProduct());
                map.put("usableQty", inventoryBatchUom.computeQty(stock.getUsableQty(), productUom,true));
                map.put("batchQty", inventoryBatchUom.computeQty(inventoryBatchQty, productUom,true));
                map.put("stockUsableQty", inventoryBatchUom.computeQty(stockQty, productUom,true));
                map.put("productSumQty", inventoryBatchUom.computeQty(productSumQty, productUom,true));
                map.put("suppliers", suppliers);
            }

            returnData.add(map);
        });
        return returnData;
    }

    public Page getPage(int page, int size, List<Map> result) {
        List<Map> pageResult;
        if (result.size() < page * size) return null;
        if (result.size() <= size * (page +1)) {
            pageResult  = result.subList(page * size,result.size());
        }else {
            pageResult  = result.subList(page * size, size * (page + 1));
        }
        Pageable pageable = PageRequest.of(page, size);
        PageImpl pageImpl = new PageImpl<>(pageResult, pageable, result.size());
        return pageImpl;
    }

    public List<TransferProduct> checkTransferProduct(List<TransferProduct> transferProducts, boolean checkHT) {
        if (transferProducts.stream().anyMatch(e->e.getSupplier() == null)) return transferProducts;

        String HT = "Contract.contractType.supplier";
        String XY = "Contract.contractType.platform";
        List<TransferProduct> transferProductList = transferProducts.stream().filter(e->{
            List<Contract> contracts = SpringManager.getBean(ContractRepository.class).findAll(
                    JpaDsl.toCriteria(
                            "company.id","in", Arrays.asList("1001", "1009"),
                            "partner.id","EQ", e.getSupplier().getId(),
                            "contractType.id","EQ", checkHT ? HT : XY,
                            "state","EQ","approve"));
            if (contracts.size() == 0) return false;
            return contracts.stream().anyMatch(contract->checkContract(contract));
        }).collect(Collectors.toList());
        return transferProductList;
    }

    public boolean checkContract(Contract contract) {
        long start = contract.getValidFrom().getTime();
        long end = contract.getValidPeriod().getTime();
        long time = new Date().getTime();
        if (start<=time && end>= time) return true;
        return false;
    }

    public List<PartyRole> findAllSupplier() {
        List<String> companyIds = getBean(BusinessParamRepository.class).findAllByQueryKey("accordingToCompanyContract").stream().map(busP -> {return busP.getValue();}).collect(Collectors.toList());
        List<Contract> contracts = SpringManager.getBean(ContractRepository.class).findAll(
                JpaDsl.toCriteria(
                        "company.id","in", companyIds,
                        "contractType.id","EQ", "Contract.contractType.supplier",
                        "state","EQ","approve"));
        List<PartyRole> suppliers = contracts.stream().filter(contract -> checkContract(contract))
                                                      .map(contract -> contract.getPartner()).collect(Collectors.toList());
        return suppliers;
    }

    public List<PartyRole> findAllSupplier(List supplierList) {
        List<String> companyIds = getBean(BusinessParamRepository.class).findAllByQueryKey("accordingToCompanyContract").stream().map(busP -> {return busP.getValue();}).collect(Collectors.toList());
        List<Contract> contracts = SpringManager.getBean(ContractRepository.class).findAll(
                JpaDsl.toCriteria(
                        "company.id","in", companyIds,
                        "contractType.id","EQ", "Contract.contractType.supplier",
                        "state","EQ","approve",
                        "partner.id", "IN", supplierList));
        List<PartyRole> suppliers = contracts.stream().filter(contract -> checkContract(contract))
                .map(contract -> contract.getPartner()).collect(Collectors.toList());
        return suppliers;
    }

    /**
     * 创建交货单
     *
     * @param request
     * @return
     */

    private Pick createPickOrder(SimpleRequest request) {
        CrossCompanyTransferNew crossData = new CrossCompanyTransferNew();
        CrossCompanyTransferNew crossCompanyTransfer = new CrossCompanyTransferNew();
        if (request.getData() != null) {
            crossData = request.getO(CrossCompanyTransferNew.class);
            crossCompanyTransfer = crossCompanyTransferRepository.findOne(crossData.getId());
        } else {
            crossCompanyTransfer = crossCompanyTransferRepository.findOne((String) request.get("id"));
        }
        Optional.ofNullable(crossCompanyTransfer).orElseThrow(() -> new RuntimeException("无法找到跨公司调拨单"));
        //创建拣配单
        Pick pick = new Pick();
        if (!Objects.isNull(crossData.getCustomerExpand())) pick.setCustomerExpandId(crossData.getCustomerExpand().getId());
        pick.setCreator("system");
        com.apes.scm.masterdata.enumeration.model.Enumeration enumeration = new Enumeration();
        enumeration.setId("direct");
        //部分交货
        pick.setMoveType(enumeration);
        // 公司为发货仓的公司
        pick.setCompany(crossCompanyTransfer.getCompany());
        //合作伙伴为收货仓的公司
        pick.setPartner(crossCompanyTransfer.getReceiptLocation().getCompany());
        pick.setLocation(crossCompanyTransfer.getShipLocation());
        pick.setReceiptLocation(crossCompanyTransfer.getReceiptLocation());
        pick.setOrigin(crossCompanyTransfer.getId());
        pick.setOriginBusinessType(crossCompanyTransfer.getInnerBusinessType());
        // 交货类型： 交货
        pick.setOperation("deliver");
        // 注入场景
//        pick.setScene(crossCompanyTransfer.getScene());
        pick.setPickItems(getPickItem(crossCompanyTransfer));
        // 创建交货单
//        EventUtil.sendSynEvent(this, "event:stock.pick.save", pick);
        invoke("stock.pick.create", MapUtil.mapped(pick));
        return pick;
    }

    /**
     * 功能：获取明细数据
     *
     * @param crossCompanyTransfer
     * @return
     */
    private Set<PickItem> getPickItem(CrossCompanyTransferNew crossCompanyTransfer) {

        Set<PickItem> pickItems =  crossCompanyTransfer.getCrossCompanyTransferItems().stream().filter(item -> {
            if (crossCompanyTransfer.getWithDrawDiveryQtySum() > 0) return item.getWithDrawDiveryQty() > 0;
            return true;
        }).map(
                (CrossCompanyTransferItemNew item) -> {
                    double qty = item.getWithDrawDiveryQty() > 0?item.getWithDrawDiveryQty():item.getProductSum();
                    PickItem pickItem = new PickItem();
                    pickItem.setProduct(item.getProduct());
                    pickItem.setUom(item.getUom());
                    pickItem.setOrderedQty(qty);
                    pickItem.setProductUomQty(qty);
                    pickItem.setOriginLine(item.getId());
                    return pickItem;
                }).collect(Collectors.toSet());
        return pickItems;
    }

    /**
     * 创建收货单
     *
     * @param request
     * @return
     */
    private Pick createReceiptPick(SimpleRequest request) {
        JSONObject param = request.getJO();
        Pick deliverPick = pickRepository.findOne(param.getString("pickId"));
//        Pick deliverPick = request.getO(Pick.class);
        Enumeration enumeration = new Enumeration();
        enumeration.setId("one");
        Pick pick = new Pick();
        pick.setCustomerExpandId(deliverPick.getCustomerExpandId());
        pick.setCreator(request.getPersonId());
        // 交货方式 direct：部分交货，one： 一次性交货
        pick.setMoveType(enumeration);
        // 设置状态
        pick.setState("confirmed");
        // 设置公司
        pick.setCompany(deliverPick.getCompany());
        // 设置仓库
        pick.setLocation(deliverPick.getReceiptLocation());
        pick.setReceiptLocation(deliverPick.getLocation());
        // 合作伙伴 发货方的公司
        pick.setPartner(deliverPick.getLocation().getCompany());
        // 不自动收货
        pick.setAuto(false);
        pick.setOrigin(deliverPick.getOrigin());
        pick.setOriginBusinessType(deliverPick.getOriginBusinessType());
        pick.setSource(deliverPick.getId());
        pick.setCustomerExpandId(deliverPick.getCustomerExpandId());
        // 交货类型：收货
        pick.setOperation("receipt");
        pick.setCreator(deliverPick.getDoneUid().getId());
        // 注入场景
//        pick.setScene(crossCompanyTransfer.getScene());

        // 明细数据，使用交货单的数量作为收货方的收货数量
        Set<PickItem> pickItems = new HashSet<>();
        for (PickItem deliverPickItem : deliverPick.getPickItems()) {
            PickItem pickItem = new PickItem();
            // 获取数量
            pickItem.setOrderedQty(deliverPickItem.getOrderedQty());//订单数量
            pickItem.setProduct(deliverPickItem.getProduct());
            pickItem.setUom(deliverPickItem.getUom());//单位
            pickItem.setProductUomQty(deliverPickItem.getQtyDone());//代办数量
            pickItem.setOriginLine(deliverPickItem.getOriginLine());//來源明細id
            pickItems.add(pickItem);
        }
        pick.setPickItems(pickItems);
        // 创建交货单
        List<Pick> responsePicks = EventUtil.sendSynEvent(this, "event:stock.pick.save", pick);
        Pick responsePick = responsePicks.get(0);
//        if (true) throw new RuntimeException("------------");
        this.writePickLog(responsePick);

        return pick;
    }

    private void writePickLog(Pick pick) {
        User user = userRepository.findAll(JpaDsl.toCriteriaByEq("person.id", pick.getCreator())).stream().findFirst().get();
        SpringManager.getBean(ApesLoggerService.class).sendSynEvent("event:ir.logger.create", MapUtil.mapper(
                "businessType", pick.getInnerBusinessType(),
                "businessKey", pick.getInnerBusinessKey(),
                "operate", "创建收货单", "operator_id", user.getId()
        ));
    }

    /**
     * 生成跨公司交易凭证
     */
    public void createVoucher(JSONObject getJO) {
        Pick pick = pickRepository.findOne(getJO.getString("pickId"));
        CrossCompanyTransferNew crossCompanyTransferNew = crossCompanyTransferRepository.findOne(getJO.getString("crossId"));
        Voucher voucher = new Voucher();
        voucher.setScene(crossCompanyTransferNew.getScene());
        voucher.setCompany(crossCompanyTransferNew.getShipLocation().getCompany());//公司
        voucher.setDept(crossCompanyTransferNew.getShipLocation().getDept());//部门
        voucher.setSourceDept(crossCompanyTransferNew.getShipLocation().getDept());//发货部门
        voucher.setReceiptDept(crossCompanyTransferNew.getReceiptLocation().getDept());//收货部门
        voucher.setPartner(crossCompanyTransferNew.getReceiptLocation().getCompany());//合作伙伴(收货仓公司)
        if (!Objects.isNull(crossCompanyTransferNew.getCustomerExpand())) voucher.setCustomerExpand(crossCompanyTransferNew.getCustomerExpand().getId());

        voucher.setOrigin(pick.getOrigin());//源单据
        voucher.setOriginBusinessType(pick.getOriginBusinessType());//源单据类型
        voucher.setSource(pick.getInnerBusinessKey());//来源单据
        voucher.setSourceBusinessType(pick.getInnerBusinessType());//来源单据类型
        voucher.setAccountingMethod(AccountingMethod.AM_PURCHASE);//核算方式
        voucher.setInventoryMode(InventoryMode.IM_OWN);//库存方式
        voucher.setVoucherType(VoucherType.CROSS_TRANSFER);//凭证类型
        voucher.setBusinessType(BusinessType.TRANSFER_ORDER);

        //拼明细
        Set<VoucherItem> voucherItems = new HashSet();
        pick.getPickItems().stream().filter(item -> item.getQtyDone() != 0).forEach(pickItem -> {
            double qty = pickItem.getQtyDone();
            boolean flag = false;
            //根据调拨单id查询调拨批次表
            List<TransferBatch> transferBatchList = transferBatchRepository.findByItem(pickItem.getOriginLine());
            for (TransferBatch transferBatch : transferBatchList) {
                if (qty == 0) break;
                //可写凭证数量
                double canVoucherQty = transferBatch.getProductQty()-transferBatch.getVoucherQty();
                if (canVoucherQty == 0) continue;
                VoucherItem voucherItem = new VoucherItem();
                //凭证数量
                if (qty >= canVoucherQty) {
                    voucherItem.setProductQty(canVoucherQty);//数量
                    qty -= canVoucherQty;
                    transferBatch.setVoucherQty(transferBatch.getVoucherQty() + canVoucherQty);
                }else {
                    voucherItem.setProductQty(qty);//数量
                    transferBatch.setVoucherQty(transferBatch.getVoucherQty() + qty);
                    qty = 0;
                }
                transferBatchRepository.saveAndFlush(transferBatch);

                voucherItem.setInventoryBatch(transferBatch.getInventoryBatch());//价值批次
                voucherItem.setTax(transferBatch.getInventoryBatch().getTax());//税种
                voucherItem.setPriceUnit(transferBatch.getInventoryBatch().getTaxCostPrice());//含税单价
                //找供应商
                InventoryBatchRepository inventoryBatchRepository = SpringManager.getBean(InventoryBatchRepository.class);
                InventoryBatch batch = inventoryBatchRepository.findOne(transferBatch.getInventoryBatch().getId());
                voucherItem.setSupplier(batch.getSupplier());//供应商
                voucherItem.setProduct(transferBatch.getProduct());//商品
                voucherItem.setUom(transferBatch.getUom());//计量单位
                voucherItem.setOwner(crossCompanyTransferNew.getShipLocation().getCompany());//所属公司
                voucherItem.setOriginItemId(pickItem.getOriginLine());//原始单据明细行
                voucherItem.setSourceItemId(String.valueOf(pickItem.getId()));//源单据明细行
                voucherItems.add(voucherItem);
            }
        });
        if (voucherItems.isEmpty()) return;
        voucher.setVoucherItems(voucherItems);

        //创建凭证
        invoke("voucher.create", MapUtil.mapped(voucher));
    }

    /**
     * 根据来源单号查询调拨单
     * @param simpleRequest
     * @param <T>
     * @return
     */
    public <T> T accordinNumberFind(SimpleRequest simpleRequest) {
        String[] customCondition = {"id", "EQ", "value", "source", "EQ", "value"};

        JSONObject getJO = simpleRequest.getJO();
        String excludesFields = "无".equals(getJO.getString("excludesFields"))?"":"purchaseItems";
        return queryCommonService.accordinNumberFindLogic(simpleRequest, crossCompanyTransferRepository, customCondition, "id", excludesFields);
    }

    /**
     * 新查询调拨单
     */
    public Page<CrossCompanyTransferNew> findAll(SimpleRequest request) {
        List<Map> condition = request.get("condition");
        Map param = condition.stream().filter(map -> "printState".equals(map.get("field").toString())).collect(Collectors.toList()).get(0);
        condition = condition.stream().filter(map -> !"printState".equals(map.get("field").toString())).collect(Collectors.toList());
        boolean flag = condition.stream().anyMatch(map -> "id".equals(map.get("field").toString()));
        List<CrossCompanyTransferNew> all = new ArrayList<>();
        if (flag) {
            all = crossCompanyTransferRepository.findAll(JpaDsl.toCriteria(condition));
            if (all.size() == 0) {
                String id = condition.stream().filter(map -> "id".equals(map.get("field").toString())).collect(Collectors.toList()).get(0).get("value").toString();
                condition = condition.stream().filter(map -> !"id".equals(map.get("field").toString())).collect(Collectors.toList());
                condition.add(mapper("field","source","value",id,"operator","EQ"));
                all = crossCompanyTransferRepository.findAll(JpaDsl.toCriteria(condition));
            }
        }else {
            all = crossCompanyTransferRepository.findAll(JpaDsl.toCriteria(condition));
        }
        convertData(all);

        if ("1".equals(param.get("value"))) {
            List<CrossCompanyTransferNew> notPrint = all.stream().filter(e -> e.getPrintNumber() == 0).collect(Collectors.toList());
            return autoPage(request,notPrint);
        } else if("2".equals(param.get("value"))) {
            List<CrossCompanyTransferNew> Print = all.stream().filter(e -> e.getPrintNumber() > 0).collect(Collectors.toList());
            return autoPage(request,Print);
        }

        return autoPage(request,all);
    }

    /**
     * 设置打印次数
     * @param all
     * @return
     */
    public List<CrossCompanyTransferNew> convertData(List<CrossCompanyTransferNew> all) {
        all.forEach(e->{
            PrintRecord printRecord = printRecordRepository.findBySource(e.getId());
            if (printRecord != null) {
                e.setPrintNumber(printRecord.getPrintNumber());
            }else {
                e.setPrintNumber(0);
            };
        });
        return all;
    }

    public Page autoPage(SimpleRequest request, List<CrossCompanyTransferNew> data) {
        List<CrossCompanyTransferNew> pageResult;
        int page = Integer.valueOf(request.get("page").toString());
        int size = Integer.valueOf(request.get("size").toString());
        if (data.size() < page*size) return null;
        if (data.size() <= size*(page +1)) {
            pageResult  = data.subList(page*size,data.size());
        }else {
            pageResult  = data.subList(page*size,size*(page +1));
        }
        Pageable pageable = PageRequest.of(request.get("page"), request.get("size"));
        PageImpl pageImpl = new PageImpl<>(pageResult, pageable, data.size());
        return pageImpl;
    }

    public CrossCompanyTransferNew findOne(SimpleRequest request) {
        String id = request.getJO().getString("id");
        CrossCompanyTransferNew companyTransferNew = crossCompanyTransferRepository.findOne(id);
        PrintRecord printRecord = printRecordRepository.findBySource(id);
        if (printRecord != null) {
            companyTransferNew.setPrintNumber(printRecord.getPrintNumber());
        }else {
            companyTransferNew.setPrintNumber(0);
        };
        return companyTransferNew;
    }

    // 导入
    public JSONObject beImport(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        JSONObject importData = getJO.getJSONObject("importData");

        // 用来查询批次
        JSONArray sheet1Array = importData.getJSONArray(importData.entrySet().iterator().next().getKey());
        Assert.isTrue(!(sheet1Array.size() > 100), "调拨导入商品上限100条！超100请从 [批量补货] 功能导入");
        List<String> productIds = new ArrayList<>();
        for (int i = 0, iLen = sheet1Array.size(); i < iLen; i++) {
            if (i == 0) continue;
            productIds.add(sheet1Array.getJSONArray(i).getString(0));
        }
        JSONObject model = getJO.getJSONObject("model");
        SimpleRequest request1 = new SimpleRequest();
        Map findInventoryCondi = MapUtil.mapper("shipLocation", model.getJSONObject("shipLocation").getString("id"), "receiptLocation", model.getJSONObject("receiptLocation").getString("id"), "importProductIds", productIds);
        request1.setData(findInventoryCondi);
        List<Map> inventoryBatchs = this.findInventoryNew(request1).getContent();


        JSONObject reutrnData = new JSONObject(); // 返回值
        importData.forEach((k, v) -> {
            List<List> returnImportProductItems = new ArrayList();

            // returnImportProductItems 第一行必须用来存 中文列
            List headerNames = getJO.getJSONArray("data").stream().map(titleChinese -> {
                return ((JSONObject) titleChinese).get("name");
            }).collect(Collectors.toList());
            returnImportProductItems.add(headerNames);

            JSONArray importProductData = (JSONArray) v; // 导入的具体数据
            JSONArray header = (JSONArray) importProductData.get(0); // 首行数据
            for (int i = 0; i < importProductData.size(); i++) {
                if (i == 0) continue;

                JSONArray importDataArray = (JSONArray) importProductData.get(i);
                if (importDataArray.size() == 0) continue; //跳过空白行

                // title 和 值 对照
                Map<String, String> keyAndValueContrast = IntStream.range(0, header.size())
                        .collect(HashMap::new,
                                (m, key) -> {
                                    m.put(header.getString(key).replace(";", ""), StringUtils.isEmpty(importDataArray.get(key))?"":importDataArray.getString(key).trim().replaceAll("[\\s]{2,}", " "));
                                }, (m1, m2) -> {
                                });


                String productId = keyAndValueContrast.get("商品");
                if (StringUtils.isEmpty(productId)) throw new RuntimeException("请按导出模板导入，请勿随意更改头部名称！");
                Product product = productRepository.findOne(productId);
                Optional.ofNullable(product).orElseThrow(() -> new RuntimeException(String.format("商品[%s]不存在", keyAndValueContrast.get("商品"))));

                // 获取相同的商品批次
                Map meetInventProducts = inventoryBatchs.stream().filter(inventoryBatch -> {
                    return ((Product) inventoryBatch.get("product")).getId().equals(productId);
                }).findFirst().orElse(new HashMap());

                // 记录未能成功导入的商品
                if (meetInventProducts == null || meetInventProducts.isEmpty()) {
                    continue;
                }

                ProductUom dumpUom = (ProductUom) meetInventProducts.get("uom");
                List a = Arrays.asList("",
                        MapUtil.mapper("id", product.getId(), "name", product.getName()),
                        MapUtil.mapper("id", dumpUom.getId(), "name", dumpUom.getName()),
                        1 / dumpUom.getFactor(),
                        meetInventProducts.get("productSumQty"),
                        Double.valueOf(keyAndValueContrast.get("调拨数量")),
                        0, 0, 0, "", "", true, meetInventProducts.get("suppliers"));
                returnImportProductItems.add(a);
            }
            reutrnData.put(k, returnImportProductItems);
        });

        return reutrnData;
    }

    public void changeTransferInBilling(CrossCompanyTransferNew companyTransferNew,int typeValue) {
        companyTransferNew.getCrossCompanyTransferItems().forEach(transferItemNew -> {
            productAccountService.setProductTransferInBilling(transferItemNew.getProduct(),
                    companyTransferNew.getReceiptLocation(), transferItemNew.getUom(), typeValue * transferItemNew.getProductSum(),
                    companyTransferNew.getReceiptLocation().getCompany());
        });
    }

    public void changeQtyByPick(Pick pick,CrossCompanyTransferNew transferNew,int typeValue) {
        pick.getPickItems().forEach(pickItem -> {
            // 发货在途
            productAccountService.setProductTransferIssue(pickItem.getProduct(),
                    transferNew.getShipLocation(), //发货仓库
                    pickItem.getUom(),
                    typeValue * pickItem.getQtyDone(),// 发货在途改变的数量(减去发货数数)
                    transferNew.getShipLocation().getCompany());

            // 收货在途
            productAccountService.setProductTransferReceive(pickItem.getProduct(),
                    transferNew.getReceiptLocation(),
                    pickItem.getUom(),
                    typeValue * pickItem.getQtyDone(),
                    transferNew.getReceiptLocation().getCompany());
        });
    }

    public void changeTransferBatchQty(Pick pick) {
        pick.getPickItems().forEach(pickItem -> {
            double qty  = pickItem.getQtyDone();
            List<TransferBatch> transferBatchList = transferBatchRepository.findByItem(pickItem.getOriginLine());
            for (TransferBatch transferBatch : transferBatchList) {
                if (qty == 0) break;
                //可发货数量
                double canShipQty = transferBatch.getProductQty() - transferBatch.getShipQty();
                if (canShipQty == 0) continue;
                if (qty >= canShipQty) {
                    transferBatch.setShipQty(transferBatch.getShipQty() + canShipQty);
                    qty -= canShipQty;
                }else {
                    transferBatch.setShipQty(transferBatch.getShipQty() + qty);
                    qty = 0;
                }

                transferBatchRepository.saveAndFlush(transferBatch);
            }
        });
    }

    public void changeCrossQty(Pick pick,CrossCompanyTransferNew transferNew) {
        pick.getPickItems().forEach(pickItem -> {
            transferNew.getCrossCompanyTransferItems().stream()
                    .filter( item -> item.getId().equals(pickItem.getOriginLine()))
                    .forEach( transferItemNew -> {
                        if("deliver".equals(pick.getOperation())) {
                            transferItemNew.setShipNum(transferItemNew.getShipNum() + pickItem.getQtyDone());  //设置发货数量
                        } else {
                            transferItemNew.setArrivalSum(transferItemNew.getArrivalSum() + pickItem.getQtyDone());   //设置到货数量
                        }
                    });
        });
    }

    public void changeCrossState(CrossCompanyTransferNew transferNew) {
        String state = "done";
        for (CrossCompanyTransferItemNew itemNew:transferNew.getCrossCompanyTransferItems()) {
            if (itemNew.getProductSum() != itemNew.getArrivalSum() + itemNew.getFinishSum()) {
                state = "approve";
            }
        }
        transferNew.setVersion(transferNew.getVersion() + 1);
        transferNew.setState(state);
        crossCompanyTransferRepository.saveAndFlush(transferNew);
    }

    public void changeTransferInBillingByPick(Pick pick,int typeValue) {
        pick.getPickItems().forEach(pickItem -> {
            productAccountService.setProductTransferInBilling(pickItem.getProduct(),
                    pick.getReceiptLocation(), pickItem.getUom(), typeValue * pickItem.getQtyDone(),
                    pick.getReceiptLocation().getCompany());
        });
    }

    // 修改打印数量
    public void updatePrintNumber(SimpleRequest request) {
        PrintRecord printRecord = request.getO(PrintRecord.class);
        String sourceBusinessTypeName = printRecord.getSourceBusinessType();
        if (!"CrossCompanyTransferNew".equals(sourceBusinessTypeName) && !"CrossCompanyTransfer".equals(sourceBusinessTypeName) && !"Transfer".equals(sourceBusinessTypeName)) return;
        if ("CrossCompanyTransferNew".equals(sourceBusinessTypeName)) {
            CrossCompanyTransferNew crossCompanyTransferNew = crossCompanyTransferRepository.findOne(printRecord.getSource());
            crossCompanyTransferNew.setLastUpdatedStamp(new Date());
            crossCompanyTransferNew.setPrintNumber(printRecord.getPrintNumber());
            crossCompanyTransferRepository.save(crossCompanyTransferNew);
        } else if ("CrossCompanyTransfer".equals(sourceBusinessTypeName)) {
            CrossCompanyTransfer crossCompanyTransfer = SpringManager.getBean(CrossCompanyTransferRepository.class).findOne(printRecord.getSource());
            crossCompanyTransfer.setLastUpdatedStamp(new Date());
            crossCompanyTransfer.setPrintNumber(printRecord.getPrintNumber());
            SpringManager.getBean(CrossCompanyTransferRepository.class).save(crossCompanyTransfer);
        } else if ("Transfer".equals(sourceBusinessTypeName)) {
            Transfer transfer = SpringManager.getBean(TransferRepository.class).findOne(printRecord.getSource());
            transfer.setLastUpdatedStamp(new Date());
            transfer.setPrintNumber(printRecord.getPrintNumber());
            SpringManager.getBean(TransferRepository.class).save(transfer);
        }

    }

    // 获取公司间单价
    public double getS950(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        String productId = getJO.getString("productId");
        String supplierId = getJO.getString("supplierId");
        Map condi = new HashMap();
        condi.put("conditionStrategyId", "GS53");
        condi.put("SYS_RQ", new Date());
        condi.put("PRODUCT_ID", productId);
        condi.put("P001", getJO.getDoubleValue("taxCostPrice"));
        condi.put("COMPANY_ID", getJO.getString("companyId"));
        condi.put("CUSTOMER_ID", getJO.getString("customerId"));
        if ("A00000".equals(supplierId)) {
            condi.put("SYS_NO_CHECK", "SUPPLIER_ID");
        } else {
            condi.put("SUPPLIER_ID", getJO.getString("supplierId"));
        }
        PartyRole customerRole = partyRoleRepository.findOne(getJO.getString("customerId"));
        if (customerRole != null) {
            String operation = this.queryOperationModel(partyRoleRepository.findByPartyIdAndRoleId(customerRole.getParty().getId(), "Company"));
            condi.put("OPERATION", "directly".equals(operation)?"001072":"subsidiary".equals(operation)?"001661":"empower".equals(operation)?"001073":"");
        }

        Product product = productRepository.findOne(productId);
        condi.put("CLASSIFY_ID", product.getClassify().getId());
        condi.put("BRAND_ID", product.getBrand().getId());
        Object obj = this.invoke("condition.execConditionStrategy", condi);
        JSONObject priceResult = JSONObject.parseObject(obj.toString());
        return priceResult.getDoubleValue("S950");
    }


    // 交货单撤回
    public void pickWithdraw(SimpleRequest request) {
        Map pick = request.getMap();
        String pickOrigin = pick.get("origin").toString();
        CrossCompanyTransferNew cross = crossCompanyTransferRepository.findOne(pickOrigin);
        List<TransferBatch> transferBatchs = transferBatchRepository.findAll(JpaDsl.toCriteriaByEq("crossCompanyTransfer.id", pickOrigin));
        ((List) pick.get("item")).stream().forEach(pickI -> {
            Map pickItem = (Map) pickI;
            double pickQtyDone = Double.valueOf(pickItem.get("qtyDone").toString());
            cross.getCrossCompanyTransferItems().stream().anyMatch(crossIte -> {
                if (pickItem.get("originItemId").toString().equals(crossIte.getId())) {
                    // 生成新的交货单数量使用此数量，在未全部发货会产生一个新的交货单，此时只需要生成一个撤回发货的数量即可
                    crossIte.setWithDrawDiveryQty(pickQtyDone);
                    cross.setWithDrawDiveryQtySum(cross.getWithDrawDiveryQtySum() + pickQtyDone);

                    // 更新调拨批次发货数量
                    this.changeCrossInventoryBatch(transferBatchs, crossIte.getId(), new AtomicDouble(pickQtyDone));

                    // 还原单据发货数量
                    crossIte.setShipNum(crossIte.getShipNum() - pickQtyDone);

                    // 减少收发货在途
                    changeStock(cross, crossIte, pickQtyDone, -1);

                    // 增加保管数
                    productAccountService.setProductCustody(crossIte.getProduct(), cross.getShipLocation(), crossIte.getUom(),
                            Math.abs(pickQtyDone), cross.getInnerBusinessType(), cross.getId(), crossIte.getId() + "", "交货撤回", cross.getShipLocation().getCompany());

                    // 增加转入制单数量
                    productAccountService.setProductTransferInBilling(crossIte.getProduct(), cross.getReceiptLocation(), crossIte.getUom(), pickQtyDone,
                            cross.getReceiptLocation().getCompany());
                    return true;
                }
                return false;
            });
        });
        //取消收货方交货单
        invoke("stock.pick.batchCancel", MapUtil.mapper("origin", pickOrigin, "source", pick.get("pickId").toString(), "cancelUid", pick.get("cancelUid")));

        CrossCompanyTransferNew newCross = crossCompanyTransferRepository.saveAndFlush(cross);

        // 生成新的交货单
        SimpleRequest createPickParam = new SimpleRequest();
        createPickParam.setData(newCross);
        this.createPickOrder(createPickParam);
    }

    /** 写入库存账的转储发货在途、转储收货在途 */
    public void changeStock(CrossCompanyTransferNew cross, CrossCompanyTransferItemNew crossItem, double qtyDOne, int typeValue) {
        // 转储发货在途
        productAccountService.setProductTransferIssue(crossItem.getProduct(), cross.getShipLocation(), crossItem.getUom(),
                typeValue * qtyDOne, cross.getCompany());
        // 转储收货在途
        productAccountService.setProductTransferReceive(crossItem.getProduct(), cross.getReceiptLocation(), crossItem.getUom(),
                typeValue * qtyDOne, cross.getCompany());
    }

    // 修改批次发货数量
    private void changeCrossInventoryBatch(List<TransferBatch> transferBatchs, String crossItemId, AtomicDouble pickQtyDone) {
        transferBatchs.stream().forEach(transferBatch -> {
            double shipQty = transferBatch.getShipQty();
            if (!transferBatch.getCompanyTransferItem().getId().equals(crossItemId) && shipQty == 0) return;
            double newShipQty = shipQty > pickQtyDone.get()?pickQtyDone.get():shipQty;
            transferBatch.setShipQty(transferBatch.getShipQty() - newShipQty);
            pickQtyDone.set(pickQtyDone.get() - newShipQty);
            transferBatchRepository.save(transferBatch);
        });
    }

    public CrossCompanyTransferNew externalCreate(SimpleRequest request) {
        CrossCompanyTransferNew cross = request.getO(CrossCompanyTransferNew.class);
        Assert.isTrue(!(cross.getCrossCompanyTransferItems().size() > 100), "调拨商品上限100条！超100请从 [批量补货] 功能导入");
        cross.setState("sent");
        cross.setCompany(cross.getShipLocation().getCompany());
        boolean empowermentToNoEmpowerment = cross.getEmpowermentToNoEmpowerment();
        boolean existsTransferProductSupplierIsNull = cross.getExistsTransferProductSupplierIsNull();
        List<String> transferProductSuppliers = cross.getTransferProductSuppliers();

        cross = crossCompanyTransferRepository.saveAndFlush(cross);

        // 找批次
        if (existsTransferProductSupplierIsNull) transferProductSuppliers = findAllSupplier().stream().distinct().map(singleSupplier -> {return singleSupplier.getId();}).collect(Collectors.toList());
        this.findInventoryBatch(cross, transferProductSuppliers, existsTransferProductSupplierIsNull, empowermentToNoEmpowerment);

        // 变动可用数、转入制单数、未达账
        changeUseQty(cross, 1);

        // 核对批次和明细是否一致
//        checkInventoryBatch(cross);
        return cross;
    }

    // 修改其他扩展表数据
    public void updateOtherTable(CrossCompanyTransferNew cross) {
        if (!"SafetyStockGap".equals(cross.getSpecialDocumentsType())) return;
        cross.getCrossCompanyTransferItems().forEach(item -> {
            Map requireExpand = MapUtil.mapper("origin", cross.getSpecialDocuments(), "originItemId", item.getOriginItemId(), "originBusinessType", cross.getSpecialDocumentsType(),
                    "productId", MapUtil.mapper("id", item.getProduct().getId()), "productUomId", MapUtil.mapper("id", item.getUom().getId()),
                    "distributionId", cross.getId(), "requireQty", item.getProductSum(), "assignQty", item.getProductSum());

            // 写入要货扩展表
            invoke("stock.productRequireExpand.save", requireExpand);

            // 修改安全库存分配数量
            this.sendUpdateGapAssignedQty(cross.getSpecialDocumentsType(), item, item.getProductSum());
        });
    }

    // 修改安全库存分配数量
    private void sendUpdateGapAssignedQty(String specialDocumentsType, CrossCompanyTransferItemNew item, double currentQty) {
        if (!"SafetyStockGap".equals(specialDocumentsType)) return;
        invoke("stock.safetyStockGapService.updateAssignedQty",
                MapUtil.mapper("id", item.getOriginItemId(), "assignedQty", currentQty, "uom", MapUtil.mapper("id", item.getUom().getId())));
    }

    // 不考虑多次终止的情况
    private void stopSendUpdateRequireExpandAssignedQty(String transferId, String specialDocumentsType, CrossCompanyTransferItemNew item) {
        if (!"SafetyStockGap".equals(specialDocumentsType)) return;
        Map requireExpand = MapUtil.mapper("originItemId", item.getOriginItemId(), "productId", MapUtil.mapper("id", item.getProduct().getId()), "productUomId", MapUtil.mapper("id", item.getUom().getId()),
                "distributionId", transferId, "cancelQty", item.getFinishSum());
        invoke("stock.productRequireExpandService.updateCancelQty", requireExpand);
    }


    // 【审核】要货批量转储修改要货明细、生成扩展表
    private void batchRequireDumpUpdateRequireQty(CrossCompanyTransferNew cross) {
        if (StringUtils.isEmpty(cross.getSpecialDocumentsType()) || !"要货补货转储新逻辑 - 后面要剔除".equals(cross.getSpecialDocumentsType())) return;
        String requireIds = cross.getBatchRequireId();
        Map data = MapUtil.mapper("id", cross.getId(), "locationId", cross.getReceiptLocation().getId(), "requireIds", requireIds,
                "specialDocumentsType", cross.getSpecialDocumentsType(), "operate", "调拨单审核", "operateInnerBusinessType", cross.getInnerBusinessType());
        List items = cross.getCrossCompanyTransferItems().stream().map(crossItem -> {
            Map m = MapUtil.mapper("id", crossItem.getId(), "productId", crossItem.getProduct().getId(), "uomId", crossItem.getUom().getId(),
                    "qty", crossItem.getProductSum());
            return m;
        }).collect(Collectors.toList());

        data.put("item", items);
        sendSynEvent("event:fn.crossCompanyTransferNewService.approve", new JSONObject(data));
    }

    // 【终止】要货批量转储修改要货明细、生成扩展表
    private void terminationNoticRequireAndRequireExpand(CrossCompanyTransferNew cross) {
        if (StringUtils.isEmpty(cross.getSpecialDocumentsType()) || !"要货补货转储新逻辑 - 后面要剔除".equals(cross.getSpecialDocumentsType())) return;
        String requireIds = cross.getBatchRequireId();
        Map data = MapUtil.mapper("id", cross.getId(), "locationId", cross.getReceiptLocation().getId(), "requireIds", requireIds, "specialDocumentsType", cross.getSpecialDocumentsType(), "operate", "调拨单终止",
                "operateInnerBusinessType", cross.getInnerBusinessType());
        List items = cross.getCrossCompanyTransferItems().stream().map(crossItem -> {
            Map m = MapUtil.mapper("id", crossItem.getId(), "productId", crossItem.getProduct().getId(), "uomId", crossItem.getUom().getId(),
                    "qty", crossItem.getFinishSum());
            return m;
        }).collect(Collectors.toList());

        data.put("item", items);
        sendSynEvent("event:fn.crossCompanyTransferNewService.termination", new JSONObject(data));
    }

    @Listener(topic = "event:fn.crossCompanyTransferNewService.findSpecialDocumentsType")
    private String findSpecialDocumentsType(SimpleRequest request) {
        JSONObject getJO = request.getJO();
        if ("CrossCompanyTransferNew".equals(getJO.getString("innerBusinessType"))) {
            CrossCompanyTransferNew cross = crossCompanyTransferRepository.findOne(request.getJO().getString("id"));
            if (Objects.isNull(cross)) return "";
            return cross.getSpecialDocumentsType();

        } else if ("Transfer".equals(getJO.getString("innerBusinessType"))) {
            Transfer transfer = getBean(TransferRepository.class).findOne(request.getJO().getString("id"));
            if (Objects.isNull(transfer)) return "";
            return transfer.getSpecialDocumentsType();
        }
        return "";
    }

    // ---------------------------------------------------------------------------------------------------------------------------
    private CrossCompanyTransferNew saveNew(SimpleRequest request) {
        CrossCompanyTransferNew cross = request.getO(CrossCompanyTransferNew.class);
        storeService.judgeFCKBJ(cross.getReceiptLocation());
        storeService.judgeFCKBJ(cross.getShipLocation());
        if (!this.canDumpReceiptLocation(cross.getShipLocation()).contains(cross.getReceiptLocation().getId())) throw new RuntimeException("收货仓不在发货仓的发货范围内，请重新选择收货仓！");

        cross.setCompany(cross.getShipLocation().getCompany()); // 发货仓库 的公司
        cross.setState("sent");

        cross = crossCompanyTransferRepository.saveAndFlush(cross);

        // 检查主数据是否过期
        this.approveCheckPreData(cross);

        // 变更批次
        this.freezeBatch(cross);

        // 变更库存
        this.reduceChangeStock(cross);

        return cross;
    }


    // 变动库存
    public void reduceChangeStock(CrossCompanyTransferNew transfer) {
        transfer.getCrossCompanyTransferItems().forEach(item -> {
            double qty = item.getProductSum();
            // 减少可用数
            productAccountService.setProductAvailable(item.getProduct(), transfer.getShipLocation(), item.getUom(), -1 * qty,
                    transfer.getInnerBusinessType(), transfer.getId(), item.getId(), "跨公司调拨保存", transfer.getCompany());

            // 增加转入制单数量
            productAccountService.setProductTransferInBilling(item.getProduct(), transfer.getReceiptLocation(), item.getUom(), qty, transfer.getReceiptLocation().getCompany());

            // 未达账
            double occurQty = productAccountService.computeQtyUnit(transfer.getCompany(), item.getProduct(), item.getUom(), item.getProductSum());
            depositInTransitService.save(transfer.getShipLocation().getCompany(), transfer.getShipLocation(), transfer.getReceiptLocation().getDepot().getDept(), transfer.getInnerBusinessType(), transfer.getInnerBusinessKey(),
                    item.getId(), item.getProduct(), occurQty, "发货");
            depositInTransitService.save(transfer.getReceiptLocation().getCompany(), transfer.getReceiptLocation(), transfer.getShipLocation().getDepot().getDept(), transfer.getInnerBusinessType(), transfer.getInnerBusinessKey(),
                    item.getId(), item.getProduct(), occurQty, "收货");
        });

    }

    // 变更批次
    public void freezeBatch(CrossCompanyTransferNew transfer) {
        Dept dept = getDept(transfer);
        transfer.getCrossCompanyTransferItems().stream().forEach(Item -> new BatchMethod<Batch>() {
            @Override
            public Iterable<Batch> wrap() {
                // 批次先经销后代销
                List<InventoryBatch> inventories = SpringManager.getBean(InventoryBatchRepository.class).findInventoryBatchForSaleOrder(transfer.getCompany(), dept, JSONArray.parseArray(Item.getSupplierId()), Item.getProduct());
                return inventoryService.wrapBatch(inventories, Item.getUom(), inventory -> inventory.getBalanceQty() - inventory.getFrostQty());
            }

            @Override
            public void succeed(Batch batch, double increment) {
                // 冻结批次
                InventoryBatch inventoryBatch = (InventoryBatch) batch.getEntity();
                changeFrostQty(inventoryBatch, Item.getUom(), abs(increment), transfer.getCompany(),
                        transfer.getInnerBusinessType(), transfer.getId(), String.valueOf(Item.getId()), "跨公司调拨保存");


                //添加调拨批次
                saveTransferBatch(Item, increment, inventoryBatch);
            }

            @Override
            public void error(double surplus) {
                throw new RuntimeException("商品：["+Item.getProduct().getId()+"]" + Item.getProduct().getName() + " 价值库存数量少 " + surplus + Item.getUom().getName() + "！");
            }
        }.execute(abs(Item.getProductSum())));
    }



    // 保存调拨批次
    private void saveTransferBatch(CrossCompanyTransferItemNew crossItem, double qty, InventoryBatch inventoryBatch) {
        TransferBatch transferBatch = new TransferBatch();
        transferBatch.setCrossCompanyTransfer(crossItem.getCrossCompanyTransfer());
        transferBatch.setCompanyTransferItem(crossItem);
        transferBatch.setProduct(crossItem.getProduct());

        transferBatch.setInventoryBatch(inventoryBatch);
        transferBatch.setUom(crossItem.getUom());
        transferBatch.setProductQty(qty);
        transferBatchService.saveAndFlush(transferBatch);
    }


    // 界面查询商品条件拼接
    private Map findInventoryNewCondi(SimpleRequest request) {
        JSONObject getJO = request.getJO();

        // 批次条件
        Group allcondi = new Group();
        List<Filter> filters;

        // 库存条件
        Group stockCondi = new Group();
        Filter stockFilter;

        // 获取仓库
        JSONArray defaultFilters = new JSONArray();
        if (getJO.containsKey("domain")) {
            defaultFilters = getJO.getJSONObject("domain").getJSONArray("filters");
        } else if (getJO.containsKey("group")) {
            defaultFilters = getJO.getJSONObject("group").getJSONArray("filters");
        }
        String ship = getJO.containsKey("shipLocation")?getJO.getString("shipLocation"):"";
        String receipt = getJO.containsKey("receiptLocation")?getJO.getString("receiptLocation"):"";
        for (int i = 0; i < defaultFilters.size(); i++) {
            JSONObject filter = (JSONObject) defaultFilters.get(i);
            switch (filter.getString("field")) {
                case "shipLocation": ship = filter.getString("value");
                    break;
                case "receiptLocation" : receipt = filter.getString("value");
            }
        }

        // 库存 - 仓库、可用数
        stockFilter = new Filter();
        stockFilter.setField("location.id");
        stockFilter.setValue(ship);
        stockFilter.setOperator("EQ");
        stockCondi.getFilters().add(stockFilter);

        stockFilter = new Filter();
        stockFilter.setField("usableQty");
        stockFilter.setValue(0);
        stockFilter.setOperator("GT");
        stockCondi.getFilters().add(stockFilter);

        // 批次 - 公司、结存数条件
        Location shipLocation = locationRepository.findOne(ship);
//        Location receiptLocation = locationRepository.findOne(receipt);
        filters = new ArrayList<>();
        Filter filter2 = new Filter();
        filter2.setField("company.id");
        filter2.setValue(shipLocation.getCompany().getId());
        filter2.setOperator("EQ");
        filters.add(filter2);

        filter2 = new Filter();
        filter2.setField("balanceQty");
        filter2.setValue(0);
        filter2.setOperator("GT");
        filters.add(filter2);
        allcondi.setFilters(filters);


        // 批次 - 获取调拨模式，组装供应商
        String export = invoke("scm.transferProductService.accordLCompanyChangeOperation", MapUtil.mapper("id", ship));
        String reception = invoke("scm.transferProductService.accordLCompanyChangeOperation", MapUtil.mapper("id", receipt));
        List<TransferProduct> transferProductList = transferProductRepository.findByALL(export, reception);
        if (transferProductList.size() == 0) throw new RuntimeException("可调拨商品配置表未找到有效供应商");
        TransferProduct transferProduct = transferProductList.stream().filter(tProduct -> tProduct.getSupplier() == null).findFirst().orElse(null);
        if (transferProduct == null) {
            Set<String> suppliers = transferProductList.stream().map(tProduct -> {return tProduct.getSupplier().getId();}).collect(Collectors.toSet());
            filter2 = new Filter();
            filter2.setField("supplier.id");
            filter2.setValue(suppliers);
            filter2.setOperator("in");
            filters.add(filter2);
        }

        // 拼接商品
        JSONArray conditions = getJO.getJSONArray("condition");
        if (conditions != null && !conditions.isEmpty()) {
            Group condition1 = new Group();
            conditions.forEach(contion -> {
                JSONObject condiObj = (JSONObject) contion;
                Filter filter = Tools.toBean(Filter.class, condiObj);
                condition1.getFilters().add(filter);
                if ("product.id".equals(condiObj.getString("field"))) {
                    filter = new Filter();
                    filter.setField("product.name");
                    filter.setOperator("like");
                    filter.setValue(condiObj.get("value"));
                    condition1.getFilters().add(filter);
                }
            });
            condition1.setOperator("or");
            allcondi.getGroups().add(condition1);
            stockCondi.getGroups().add(condition1);

        } else if (getJO.containsKey("key")) {
            Group condition1 = new Group();
            filters = new ArrayList<Filter>();
            Filter filter1 = new Filter();
            filter1.setField("product.id");
            filter1.setOperator("like");
            filter1.setValue(getJO.get("key"));
            filters.add(filter1);

            filter1 = new Filter();
            filter1.setField("product.name");
            filter1.setOperator("like");
            filter1.setValue(getJO.get("key"));
            filters.add(filter1);

            condition1.setOperator("or");
            condition1.setFilters(filters);
            allcondi.getGroups().add(condition1);
            stockCondi.getGroups().add(condition1);
        } else if (getJO.containsKey("importProductIds")) { // 来自导入
            filter2 = new Filter();
            filter2.setField("product.id");
            filter2.setOperator("in");
            filter2.setValue(getJO.getJSONArray("importProductIds"));
            allcondi.getFilters().add(filter2);
            stockCondi.getFilters().add(filter2);
        }
        return MapUtil.mapper("stockCondi", stockCondi, "allcondi", allcondi, "export", export, "reception", reception, "receiptLocation", receipt, "shipLocation", ship);
    }


    // 商品查询
    public Page findInventoryNew(SimpleRequest request) {

        // 拼接查询条件
        Map condi = this.findInventoryNewCondi(request);
        Group allcondi = (Group) condi.get("allcondi");
        Group stockCondi = (Group) condi.get("stockCondi");
        String export = (String) condi.get("export");
        String reception = (String) condi.get("reception");

        // 查找批次
        Specification specification = allcondi.build(false);
        List<InventoryBatch> inventoryBatchList = inventoryBatchRepository.findAll(specification);

        // 过滤批次
        long receiptPartyId = locationRepository.findOne(condi.get("receiptLocation").toString()).getCompany().getParty().getId();
        String shipCompanyId = locationRepository.findOne(condi.get("shipLocation").toString()).getCompany().getId();
        Set<String> supplierIds = new HashSet<>();
        List<InventoryBatch> meetCondiInventBatchs = inventoryBatchList.stream().filter(inventoryBatch -> {
            supplierIds.add(inventoryBatch.getSupplier().getId());
            return this.judgeInventoryContract(export, reception, inventoryBatch, receiptPartyId, shipCompanyId);
        }).collect(Collectors.toList());
        if (meetCondiInventBatchs.isEmpty()){
//            throw new RuntimeException("请检查【商品是否有库存、批次】<br/> 采购合同、平台协议是否过期, 供应商：" + supplierIds.toString());
            throw new RuntimeException("没有找到满足条件的库存或批次信息，可能是以下原因：<br/>"+
                    "1、供应商为【A00000】期初供应商，期初库存只能本公司消化，不能调拨！<br/>" +
                    "2、供应商【" + supplierIds.toString() + "】的采购合同、平台协议是否过期？<br/>" +
                    "3、不满足【调拨范围】的要求。");
        }


        // 获取库存账
        Specification stockCondiSpecification = stockCondi.build(false);
        List<Stock> stocks = stockRepository.findAll(stockCondiSpecification);

        List<Map> result = setData(stocks, meetCondiInventBatchs);

        int page = Integer.valueOf(!request.getJO().containsKey("page")?"0":request.get("page").toString());
        int size = Integer.valueOf(!request.getJO().containsKey("size")?"999":request.get("size").toString());
        return getPage(page, size, result);
    }

    private boolean judgeInventoryContract(String export, String reception, InventoryBatch inventoryBatch, long receiptCompanyPartyId, String shipCompanyId) {
        if ("001073".equals(export) && "001072".equals(reception)) { // [赋能 - 直营] + 代销 + 合同
            if ("consignment".equals(inventoryBatch.getCooperation().getId())) {
                List<Contract> contracts = contractRepository.findValidPlatformSupplierState(inventoryBatch.getSupplier());
                return !contracts.isEmpty();
            } else if (inventoryBatch.getSupplier().getParty().getCorporate().inner()) {
                return true;
            } else {
                return false;
            }
        } else if ("001073".equals(export) && "001073".equals(reception)) { // [赋能 - 直营 - 赋能] + 非内部供应商 + 协议
            String supplierId = inventoryBatch.getSupplier().getId();
            PartyRole partyRold = partyRoleRepository.findInnerSupplier(supplierId);
            if (partyRold != null) {
                return true;
            } else {
                List<Contract> contracts = contractRepository.findValidPlatformState(inventoryBatch.getSupplier());
                return !contracts.isEmpty();
            }
        } else if ("001661".equals(export) && "001072".equals(reception)) {
            long supplierPartyId = inventoryBatch.getSupplier().getParty().getId();
            PartyRole supplierCompany = partyRoleRepository.findOne(JpaDsl.toCriteriaByEq("party.id", supplierPartyId, "role.id", "Company")).orElse(null);
            return (inventoryBatch.getSupplier().getParty().getCorporate().inner() && !shipCompanyId.equals(supplierCompany.getId()))
                    || inventoryBatch.getSupplier().getParty().getId() == receiptCompanyPartyId;
        }
        return true;
    }

    public String queryOperationModel(PartyRole company) {
        String operationModel = "";
        try {
            operationModel = crossTransferVoucherBuilder.getModel(company);
        }  catch (Exception e) {
            throw new RuntimeException(String.format("公司：%s[%s] 获取运营模式异常！<br/> 请检查赋能公司是否有签署【赋能合同】<br/>直营、子公司是否有签署【采购合同】", company.getName(), company.getId()));
        }
        return operationModel;
    }

    public JSONObject printOne(SimpleRequest request) {
        String id = request.getJO().getString("id");
        CrossCompanyTransferNew crossCompanyTransferNew = crossCompanyTransferRepository.findOne(request.getJO().getString("id"));
        List<CrossCompanyTransferItemNew> crossItemNews = crossCompanyTransferItemNewRepository.findTransferId(id);
        JSONObject crossNew = new JSONObject();
        Map main = MapUtil.mapped(crossCompanyTransferNew);
        main.remove("crossCompanyTransferItems");

        List<Map> crossItems = MapUtil.mapped(crossItemNews);
        for (int i = 0, iLen = crossItems.size(); i < iLen; i++) {
            Map singleCrossItem = crossItems.get(i);
            singleCrossItem.put("XH", i+1);
        }
        main.put("crossCompanyTransferItems", crossItems);

        crossNew.putAll(main);
        return crossNew;
    }
}




























